#include <iostream>
#include <memory>
#include <poll.h>
#include "Log.hpp"
#include "socket.hpp"

const int default_backlog = 5;
class PollServer
{
private:
    void HanderAccept()
    {
        // 可能会处理多个文件描述符
        for (size_t i = 0; i < _num; i++)
        {

            if (_rfds[i].fd == -1)
            {
                continue;
            }
            // 合法的套接字
            else
            {
                // 注意这里会出现：1.Accept新链接  2.read获取到新数据
                int fd = _rfds[i].fd;
                short revents = _rfds[i].revents;

                if (revents & POLLIN)
                {
                    // 表示 获取套接字就绪
                    if (fd == _listen_sock->GetSockFd())
                    {
                        lg.LogMessage(Info, "get a new link\n");
                        std::string client_ip;
                        uint16_t client_port;
                        NetWork::Socket *sock = _listen_sock->AcceptConnection(&client_ip, &client_port);
                        // 获取通信套接字失败
                        if (sock->GetSockFd() == -1)
                        {
                            lg.LogMessage(Error, "sock accept failed\n");
                            continue;
                        }
                        lg.LogMessage(Info, "connect client success, client info is %s:%d, fd = %d\n", client_ip.c_str(), client_port, sock->GetSockFd());

                        // 和select的本质逻辑一致
                        int pos = 0;

                        for (; pos < _num; pos++)
                        {
                            if (_rfds[pos].fd == -1)
                            {
                                _rfds[pos].fd = sock->GetSockFd();
                                _rfds[pos].events |= POLLIN;
                                break;
                            }
                        }
                        if (pos == _num)
                        {
                            // 服务器poll托管套接字已达上限
                            // 1.方式一：允许有上限大小
                            sock->CloseSockFd();
                            delete sock;
                            lg.LogMessage(Warning, "server is full...\n");
                            // 2.方式二：通过扩容实现无上限
                        }
                    }
                    // 表示 读取数据 就绪, 可以在这里进行IO
                    else
                    {
                        char buffer[1024];
                        ssize_t m = recv(fd, buffer, sizeof(buffer) - 1, 0);
                        if (m > 0)
                        {
                            buffer[m] = 0;
                            std::cout << "client message: " << buffer << std::endl;
                        }
                        else if (m == 0)
                        {
                            lg.LogMessage(Info, "data recv ");
                        }
                        else
                        {
                            // 差错处理 client文件描述符关闭 或者是 recv出现错误
                            lg.LogMessage(Error, "recv message failed\n");
                            close(fd);
                            // 取消poll关心事件
                            _rfds[i].fd = -1;
                            _rfds[i].events = 0;
                            _rfds[i].revents = 0;
                        }
                    }
                }
            }
        }
    }

public:
    PollServer(int port) : _port(port), _num(1024), _listen_sock(new NetWork::TcpSocket()), _isrunning(false) {}
    ~PollServer() { delete[] _rfds; }
    void InitServer()
    {
        _listen_sock->BuildListenSocketMethod(_port, default_backlog);

        _rfds = new struct pollfd[_num];
        for (size_t i = 0; i < _num; i++)
        {
            _rfds[i].fd = -1;
            // 将关心的内容设为空
            _rfds[i].events = 0;
            _rfds[i].revents = 0;
        }
        // 初始化时只有listen sock一个文件描述符
        _rfds[0].fd = _listen_sock->GetSockFd();
        // 关心事件events设置为读
        _rfds[0].events |= POLLIN;
    }

    void Loop()
    {
        _isrunning = true;
        while (_isrunning == true)
        {

            int timeout = 1000;
            int n = poll(_rfds, _num, timeout);

            if (n > 0) // poll成功
            {
                lg.LogMessage(Info, "poll success\n");
                // 这里对响应的Accept进行处理
                HanderAccept();
            }
            else if (n == 0) // poll超时
            {
                lg.LogMessage(Info, "poll timeout\n");
            }
            else // poll失败
            {
                lg.LogMessage(Error, "select error\n");
            }
        }
        _isrunning = false;
    }

private:
    std::unique_ptr<NetWork::Socket> _listen_sock;
    int _port;
    bool _isrunning;

    struct pollfd *_rfds;
    int _num;
};